package com.mapforge.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.Scanner;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

import com.mapforge.ActionCommands;
import com.mapforge.Constants;
import com.mapforge.io.IOHandlerManager;
import com.mapforge.listener.TileMapCreationEvent;
import com.mapforge.listener.TileMapCreationListener;

public class MapEditorMenuBar extends JMenuBar implements
		TileMapCreationListener {

	/**
	 * Default serial version ID, here to remove warnings.
	 */
	private static final long serialVersionUID = 1L;

	private JMenu fileMenu;
	private JMenu editMenu;
	private JMenu viewMenu;
	private JMenu helpMenu;
	private JMenu windowMenu;

	private JMenuItem file_newMapItem;
	private JMenuItem file_newTilesetItem;
	private JMenuItem file_openMapItem;
	private JMenuItem file_saveMapItem;
	private JMenuItem file_saveMapAsItem;
	private JMenuItem file_saveTilesetAsItem;
	private JMenuItem file_exitItem;

	private JMenuItem edit_undoItem;
	private JMenuItem edit_redoItem;
	private JMenuItem edit_newLayerItem;
	private JMenuItem edit_resizeItem;
	private JMenuItem edit_tilesetItem;
	private JMenuItem edit_cutTiles;
	private JMenuItem edit_copyTiles;
	private JMenuItem edit_pasteTiles;

	private JMenuItem help_aboutItem;

	public MapEditorMenuBar() {
		PreviousMapMenuItemListener listener = new PreviousMapMenuItemListener();
		fileMenu = new JMenu("File");
		editMenu = new JMenu("Edit");
		viewMenu = new JMenu("View");
		windowMenu = new JMenu("Window");
		helpMenu = new JMenu("Help");

		file_newMapItem = createStrokeItem("New Map", KeyStroke.getKeyStroke(
				KeyEvent.VK_N, ActionEvent.CTRL_MASK), 'N',
				ActionCommands.NEW_MAP_CMD);
		file_newTilesetItem = createStrokeItem("New Tileset", KeyStroke
				.getKeyStroke(KeyEvent.VK_T, ActionEvent.CTRL_MASK), 'T',
				ActionCommands.NEW_TILESET_CMD);

		file_openMapItem = createStrokeItem("Open", KeyStroke.getKeyStroke(
				KeyEvent.VK_O, ActionEvent.CTRL_MASK), 'O',
				ActionCommands.OPEN_MAP_CMD);
		file_saveMapItem = createStrokeItem("Save Map", KeyStroke.getKeyStroke(
				KeyEvent.VK_S, ActionEvent.CTRL_MASK), 'S',
				ActionCommands.SAVE_MAP_CMD);
		file_saveMapItem.setEnabled(false);

		file_saveMapAsItem = createStrokeItem("Save Map As...", KeyStroke
				.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK
						| ActionEvent.SHIFT_MASK),
				ActionCommands.SAVE_MAP_AS_CMD);
		file_saveMapAsItem.setEnabled(false);

		file_saveTilesetAsItem = createStrokeItem("Save Tileset As...",
				KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK
						| ActionEvent.ALT_MASK),
				ActionCommands.SAVE_TILESET_AS_CMD);
		file_saveTilesetAsItem.setEnabled(false);

		file_exitItem = createStrokeItem("Exit", KeyStroke.getKeyStroke(
				KeyEvent.VK_ESCAPE, 0), 'E', ActionCommands.EXIT_APP_CMD);

		fileMenu.add(file_newMapItem);
		//fileMenu.add(file_newTilesetItem);
		fileMenu.add(file_openMapItem);
		fileMenu.addSeparator();
		fileMenu.add(file_saveMapItem);
		fileMenu.add(file_saveMapAsItem);
		fileMenu.add(file_saveTilesetAsItem);

		File prevFileData = null;
		Scanner scanner = null;
		try {
			boolean firstItem = true;
			prevFileData = new File("Data/recentfiles.dat");
			if (prevFileData.exists()) {
				scanner = new Scanner(prevFileData);
				int count = 0;
				IOHandlerManager ioManager = IOHandlerManager.getHandle();
				while (scanner.hasNextLine()
						&& count < IOHandlerManager.MAX_RECENT_FILES) {
					String absPath = scanner.next();
					String mapName = scanner.next();
					File f = new File(absPath);
					// if (f.exists()) {
					if (firstItem) {
						fileMenu.addSeparator();
						firstItem = false;
					}
					PreviousMapMenuItem item = new PreviousMapMenuItem(
							(char) ('0' + count), mapName, f);
					item.addActionListener(listener);
					fileMenu.add(item);
					ioManager.addRecentFile(f, mapName);
					// }
					count++;
				}
			} else {
				System.out.println("Couldn't locate previous file data");
				// Previous files not found
			}
		}
		// need error log in future
		catch (IOException e) {
			// TODO error logging
		}
		// didn't match expected format, delete old file
		catch (NoSuchElementException e2) {
			if (prevFileData != null && prevFileData.exists()) {
				scanner.close();
				prevFileData.delete();
			}
		}

		fileMenu.addSeparator();
		fileMenu.add(file_exitItem);

		edit_undoItem = createStrokeItem("Undo", KeyStroke.getKeyStroke(
				KeyEvent.VK_Z, ActionEvent.CTRL_MASK), 'U');
		edit_undoItem.setEnabled(false);
		edit_redoItem = createStrokeItem("Redo", KeyStroke.getKeyStroke(
				KeyEvent.VK_Y, ActionEvent.CTRL_MASK), 'R');
		edit_redoItem.setEnabled(false);
		edit_cutTiles = createStrokeItem("Cut Tiles", KeyStroke.getKeyStroke(
				KeyEvent.VK_X, ActionEvent.CTRL_MASK), 'C');
		edit_cutTiles.setEnabled(false);
		edit_cutTiles.setActionCommand(ActionCommands.CUT_TILES_CMD);

		edit_copyTiles = createStrokeItem("Copy Tiles", KeyStroke.getKeyStroke(
				KeyEvent.VK_C, ActionEvent.CTRL_MASK), 'Y');
		edit_copyTiles.setActionCommand(ActionCommands.COPY_TILES_CMD);
		edit_copyTiles.setEnabled(false);

		edit_pasteTiles = createStrokeItem("Paste Tiles", KeyStroke
				.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK), 'P');
		edit_pasteTiles.setEnabled(false);
		edit_pasteTiles.setActionCommand(ActionCommands.PASTE_TILES_CMD);

		edit_resizeItem = createStrokeItem("Resize", KeyStroke.getKeyStroke(
				KeyEvent.VK_W, ActionEvent.CTRL_MASK), 'Z');
		edit_resizeItem.setEnabled(false);
		edit_newLayerItem = createStrokeItem("New Layer", KeyStroke
				.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK
						| ActionEvent.SHIFT_MASK), 'N');
		edit_newLayerItem.setEnabled(false);
		// TODO finish edit tileset dialog
		edit_tilesetItem = createStrokeItem("Tileset...", KeyStroke
				.getKeyStroke(KeyEvent.VK_T, ActionEvent.CTRL_MASK
						| ActionEvent.SHIFT_MASK), 'T',
				ActionCommands.EDIT_CURRENT_TILESET_CMD);
		edit_tilesetItem.setEnabled(false);

		//editMenu.add(edit_undoItem);
		//editMenu.add(edit_redoItem);
		editMenu.addSeparator();
		editMenu.add(edit_cutTiles);
		editMenu.add(edit_copyTiles);
		editMenu.add(edit_pasteTiles);
		editMenu.addSeparator();
		editMenu.add(edit_resizeItem);
		editMenu.add(edit_newLayerItem);
		// editMenu.add(edit_tilesetItem);

		help_aboutItem = createItem("About " + Constants.APP_TITLE);

		helpMenu.add(createItem("Welcome"));
		// helpMenu.add(createItem("Search"));
		helpMenu.add(createItem("Help"));
		helpMenu.add(help_aboutItem);

		add(fileMenu);
		add(editMenu);
		// add(viewMenu);
		add(helpMenu);
	}

	private JMenuItem createStrokeItem(String name, KeyStroke ks) {
		JMenuItem i = createItem(name);
		i.setAccelerator(ks);
		return i;
	}

	private JMenuItem createStrokeItem(String name, KeyStroke ks, char mnemonic) {
		JMenuItem i = createItem(name);
		i.setAccelerator(ks);
		i.setMnemonic(mnemonic);
		return i;
	}

	private JMenuItem createStrokeItem(String name, KeyStroke ks,
			char mnemonic, String actioncommand) {
		JMenuItem i = createStrokeItem(name, ks, mnemonic);
		i.setActionCommand(actioncommand);
		return i;
	}

	private JMenuItem createStrokeItem(String name, KeyStroke ks,
			String actioncommand) {
		JMenuItem i = createStrokeItem(name, ks);
		i.setActionCommand(actioncommand);
		return i;
	}

	private JMenuItem createItem(String name) {
		JMenuItem i = new JMenuItem(name);
		return i;
	}

	public JMenu getWindowMenu() {
		return windowMenu;
	}

	public JMenu getHelpMenu() {
		return helpMenu;
	}

	public JMenu getEditMenu() {
		return editMenu;
	}

	public JMenu getViewMenu() {
		return viewMenu;
	}

	public JMenu getFileMenu() {
		return fileMenu;
	}

	public JMenuItem getNewMapItem() {
		return file_newMapItem;
	}

	public JMenuItem getSaveMapItem() {
		return this.file_saveMapItem;
	}

	public JMenuItem getSaveMapAsItem() {
		return this.file_saveMapAsItem;
	}

	public JMenuItem getSaveTilesetAsItem() {
		return this.file_saveTilesetAsItem;
	}

	public JMenuItem getEditTilesetItem() {
		return this.edit_tilesetItem;
	}

	public JMenuItem getNewTilesetItem() {
		return file_newTilesetItem;
	}

	public JMenuItem getOpenMapItem() {
		return this.file_openMapItem;
	}

	public JMenuItem getExitItem() {
		return this.file_exitItem;
	}

	public JMenuItem getNewTileLayerItem() {
		return this.edit_newLayerItem;
	}

	public JMenuItem getCutItem() {
		return this.edit_cutTiles;
	}

	public JMenuItem getCopyItem() {
		return this.edit_copyTiles;
	}

	public JMenuItem getPasteItem() {
		return this.edit_pasteTiles;
	}

	public JMenuItem getAboutItem() {
		return this.help_aboutItem;
	}

	public JMenuItem getUndoItem() {
		return this.edit_undoItem;
	}

	public JMenuItem getRedoItem() {
		return this.edit_redoItem;
	}

	public JMenuItem getMapResizeItem() {
		return this.edit_resizeItem;
	}

	private void initForMap(boolean val) {
		this.file_saveMapAsItem.setEnabled(val);
		this.file_saveMapItem.setEnabled(val);
		this.file_saveTilesetAsItem.setEnabled(val);
		this.edit_undoItem.setEnabled(val);
		edit_redoItem.setEnabled(val);
		edit_cutTiles.setEnabled(val);
		edit_copyTiles.setEnabled(val);
		edit_pasteTiles.setEnabled(val);
		this.edit_resizeItem.setEnabled(val);
		this.edit_tilesetItem.setEnabled(val);
		this.edit_newLayerItem.setEnabled(val);
	}

	public void tileMapCreationPerformed(TileMapCreationEvent event) {
		initForMap(true);
	}

	private class PreviousMapMenuItemListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			Object obj = e.getSource();
			if (obj instanceof PreviousMapMenuItem) {
				PreviousMapMenuItem item = (PreviousMapMenuItem) obj;
				File file = item.prevFile;
				if (file.exists()) {
					IOHandlerManager ioManager = IOHandlerManager.getHandle();
					try {
						ioManager.loadTileMap(file);
					} catch (IOException exception1) {
						JOptionPane.showMessageDialog(null, exception1
								.getMessage(), "Read Error",
								JOptionPane.ERROR_MESSAGE);
						fileMenu.remove(item);
						ioManager.removeRecentFile(item.prevFile);
					}
				}
			}
		}
	}

	private class PreviousMapMenuItem extends JMenuItem {
		/**
		 * Default Serial version ID, here to remove warnings.
		 */
		private static final long serialVersionUID = 1L;
		File prevFile;
		String mapName;
		private String shortFileName;

		public PreviousMapMenuItem(char mnemonic, String mapName, File prevFile) {
			this.mapName = mapName;
			this.prevFile = prevFile;
			shortFileName = prevFile.getAbsolutePath();
			if (shortFileName.length() > 20) {
				shortFileName = shortFileName.substring(0, 20) + "...";
			}
			this.setMnemonic(mnemonic);
			this.setText(mnemonic + " - " + mapName + " [" + shortFileName
					+ "]");
		}
	}
}